﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace OME
{
   class TradingClient
   {
      Socket mdcSocket;
      byte[] receiveBuffer;
      byte[] sendBuffer;
      string [] currentTickers;
      IPAddress groupAddress;
      MulticastOption mcastOption;
      EndPoint localEP;
      IPHostEntry entry;
      BizDomain domain;
      string Id;

      public TradingClient(BizDomain BizDomain, string trader)
      {
         Id = trader;
         domain = BizDomain;
         receiveBuffer = new byte[512];
         sendBuffer = new byte[512];
         groupAddress = IPAddress.Parse("224.5.6.7");
         mcastOption = new MulticastOption(groupAddress);
         currentTickers = domain.oprocNames;
        
      }

      public void getInput()
      {
         bool check = false;
         Console.Write("Enter Symbol:  ");
         string serv = (string)Console.ReadLine();
         serv = serv.ToUpper();
         while (serv != null)
         {
            for (int i = 0; i < currentTickers.Length; i++)
            {
               if (serv.Equals(currentTickers[i]))
               {               
                  check = true;
                  break;
               }
            }
            if (check)
               break;
            if (check == false)
            {
               Console.WriteLine("You entered an invalid symbol!  Please re-enter symbol");
               serv = (string)Console.ReadLine();
               serv = serv.ToUpper();
            }
         } 
       
         if(check)
            getQuotes(serv);
         check = false;
      }

      private void getQuotes(string service)
      {
         Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
         mSocket.Connect(mdpEP);

         sendBuffer = Encoding.ASCII.GetBytes(service);
         mSocket.Send(sendBuffer);
         Console.WriteLine("getting service: " + service);
         Console.WriteLine("");
         receiveMultiCast();
         mSocket.Close();
      }

      public void receiveMultiCast()
      {         
         EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
         mdcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
         mdcSocket.Bind(localEP);
         mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);
         int check = 1;
         int tracker = 0;
         bool full = false;
         string[] orderInfo = new string[6];       
         while (check > 0)
         {
            int bytesReceived = mdcSocket.ReceiveFrom(receiveBuffer, ref endPoint);
            check = bytesReceived;
            IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
            int index=0;          
            string mktPrice = Encoding.ASCII.GetString(receiveBuffer, index, bytesReceived);
            if (mktPrice.Contains("?"))
            {
               check = mktPrice.Length - 1;
               mktPrice = mktPrice.Remove(check);
               orderInfo[tracker] = mktPrice;
               OME.Storage.ServiceOrder s = ConstructOrder(orderInfo);
               OME.Storage.Order o = (OME.Storage.Order)s;
               Console.WriteLine(o.ToString());
               domain.SubmitOrder(s.Instrument, s);
               check = 0;
            }           
            if (tracker == 5)
            {
               orderInfo[tracker] = mktPrice;
               index += mktPrice.Length;
               OME.Storage.ServiceOrder s = ConstructOrder(orderInfo);
               OME.Storage.Order o = (OME.Storage.Order)s;
               Console.WriteLine(o.ToString());
               domain.SubmitOrder(s.Instrument, s);
               full = true;
            }
            else
            {
               orderInfo[tracker] = mktPrice;
               index += mktPrice.Length;
            }

            tracker++;


            if (full == true)
            {
               tracker = 0;
               full = false;
            }

         }
         Console.WriteLine();
         //Console.WriteLine("Market Data Producer IP Address {0} Port {1} ", mdpEndPoint.Address.ToString(), mdpEndPoint.Port);
         //mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mcastOption);
         Console.WriteLine("Closing multicast socket");
         orderInfo = null;
         //tracker = 0;
         mdcSocket.Close();
         Thread input = new Thread(getInput);
         input.Start();
         //getInput();	
      }

      private OME.Storage.ServiceOrder ConstructOrder(string[] mktOrder)
      {
         string id = mktOrder[0];
         string inst = mktOrder[1];
         string type = mktOrder[2];
         string bs = mktOrder[3];
         int quant = Int32.Parse(mktOrder[4]);
         double price = Double.Parse(mktOrder[5]);
         
         OME.Storage.ServiceOrder serv = new Storage.ServiceOrder(id, inst, type, bs, price, quant);
         return serv;
      }

      public void Start()
      {
         Console.WriteLine("Market-Data Consumer Service Started - (Using MultiCast)");	
         byte[] receiveBuffer = new byte[512];
         entry = Dns.GetHostByName(Dns.GetHostName());
		   localEP = new IPEndPoint(entry.AddressList[0],30002);
		   
         //test code to change up what services we are generating
         Console.WriteLine("Please enter the service you wish to see");
         Console.WriteLine("Available Services are:");
         for (int i = 0; i < currentTickers.Length; i++)
            Console.WriteLine(currentTickers[i]);

         //getInput();
         getQuotes("FIRE");

      }

		public static void DisableMulticastLoopBack(Socket sockInstance)
		{
			sockInstance.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastLoopback,0);
		}
   }
}
